﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vds2465Telegrams;

namespace Vds2465Parser
{
	internal static class GenParse_ReportType
	{
		#region private constants

    	private const byte OnOffFlag_On = 0x00;
		private const byte OnOffFlag_Off = 0x80;

		#endregion private constants

        #region internal methods

        internal static byte GenerateByte(ReportType_Base reportTypeBase)
		{
			byte resultByte = 0x0;

			resultByte += reportTypeBase.OnOffFlag ? OnOffFlag_On : OnOffFlag_Off;

			Type reportType_Type = reportTypeBase.GetType();

            if (reportType_Type == typeof(ReportType_Device))
            {
                ReportType_Device reportType = reportTypeBase as ReportType_Device;
                byte specificByte = GenParse_ReportType_Device.GenerateByte(reportType);
                resultByte |= specificByte;
                return resultByte;
            }

            if (reportType_Type == typeof(ReportType_Disruption))
            {
                ReportType_Disruption reportType = reportTypeBase as ReportType_Disruption;
                byte specificByte = GenParse_ReportType_Disruption.GenerateByte(reportType);
                resultByte |= specificByte;
                return resultByte;
            }

            if (reportType_Type == typeof(ReportType_Fire))
            {
                ReportType_Fire reportType = reportTypeBase as ReportType_Fire;
                byte specificByte = GenParse_ReportType_Fire.GenerateByte(reportType);
                resultByte |= specificByte;
                return resultByte;
            }

			if (reportType_Type == typeof(ReportType_General))
			{
				ReportType_General reportTypeGeneral = reportTypeBase as ReportType_General;
				byte specificByte = GenParse_ReportType_General.GenerateByte(reportTypeGeneral);
				resultByte |= specificByte;
				return resultByte;
			}

            if (reportType_Type == typeof(ReportType_Intrusion))
            {
                ReportType_Intrusion reportType = reportTypeBase as ReportType_Intrusion;
                byte specificByte = GenParse_ReportType_Intrusion.GenerateByte(reportType);
                resultByte |= specificByte;
                return resultByte;
            }

            if (reportType_Type == typeof(ReportType_Proprietary))
            {
                ReportType_Proprietary reportType = reportTypeBase as ReportType_Proprietary;
                byte specificByte = GenParse_ReportType_Proprietary.GenerateByte(reportType);
                resultByte |= specificByte;
                return resultByte;
            }

            if (reportType_Type == typeof(ReportType_State))
            {
                ReportType_State reportType = reportTypeBase as ReportType_State;
                byte specificByte = GenParse_ReportType_State.GenerateByte(reportType);
                resultByte |= specificByte;
                return resultByte;
            }

            if (reportType_Type == typeof(ReportType_Technical))
            {
                ReportType_Technical reportType = reportTypeBase as ReportType_Technical;
                byte specificByte = GenParse_ReportType_Technical.GenerateByte(reportType);
                resultByte |= specificByte;
                return resultByte;
            }

			// TODO handle error (unknown ReportType sub type)
			return resultByte;
		}

		internal static bool ParseByte(byte reportTypeByteValue, out ReportType_Base reportType)
		{
			reportType = null;

			// MSB only
			byte msbOnly = (byte) (reportTypeByteValue & 0x80);

			bool onOffFlagValue;
			if (msbOnly == OnOffFlag_On) { onOffFlagValue = true; }
			else if (msbOnly == OnOffFlag_Off) { onOffFlagValue = false;}
			else
			{
				return false;
			}

            // bits 6,5,4
            byte bits654 = (byte)(reportTypeByteValue & 0x70);

            if (bits654 == GenParse_ReportType_Device.MsgBlockOnlyValue)
            {
                eReportSubType_Device reportSubType;
                bool bRetVal = GenParse_ReportType_Device.ParseByte(reportTypeByteValue, out reportSubType);
                if (bRetVal)
                {
                    reportType = new ReportType_Device(onOffFlagValue, reportSubType);
                    return true;
                }

                // TODO handle error (parsing has failed)
                return false;
            }

            if (bits654 == GenParse_ReportType_Disruption.MsgBlockOnlyValue)
            {
                eReportSubType_Disruption reportSubType;
                bool bRetVal = GenParse_ReportType_Disruption.ParseByte(reportTypeByteValue, out reportSubType);
                if (bRetVal)
                {
                    reportType = new ReportType_Disruption(onOffFlagValue, reportSubType);
                    return true;
                }

                // TODO handle error (parsing has failed)
                return false;
            }

            if (bits654 == GenParse_ReportType_Fire.MsgBlockOnlyValue)
            {
                eReportSubType_Fire reportSubType;
                bool bRetVal = GenParse_ReportType_Fire.ParseByte(reportTypeByteValue, out reportSubType);
                if (bRetVal)
                {
                    reportType = new ReportType_Fire(onOffFlagValue, reportSubType);
                    return true;
                }

                // TODO handle error (parsing has failed)
                return false;
            }

			if (bits654 == GenParse_ReportType_General.MsgBlockOnlyValue)
			{
				eReportSubType_General reportSubType;
				bool bRetVal = GenParse_ReportType_General.ParseByte(reportTypeByteValue, out reportSubType);
				if (bRetVal)
				{
					reportType = new ReportType_General(onOffFlagValue, reportSubType);
					return true;
				}

				// TODO handle error (parsing has failed)
				return false;
			}

            if (bits654 == GenParse_ReportType_Intrusion.MsgBlockOnlyValue)
            {
                eReportSubType_Intrusion reportSubType;
                bool bRetVal = GenParse_ReportType_Intrusion.ParseByte(reportTypeByteValue, out reportSubType);
                if (bRetVal)
                {
                    reportType = new ReportType_Intrusion(onOffFlagValue, reportSubType);
                    return true;
                }

                // TODO handle error (parsing has failed)
                return false;
            }

            if (bits654 == GenParse_ReportType_Proprietary.MsgBlockOnlyValue)
            {
                byte proprietaryNibble;
                bool bRetVal = GenParse_ReportType_Proprietary.ParseByte(reportTypeByteValue, out proprietaryNibble);
                if (bRetVal)
                {
                    reportType = new ReportType_Proprietary(onOffFlagValue, proprietaryNibble);
                    return true;
                }

                // TODO handle error (parsing has failed)
                return false;
            }

            if (bits654 == GenParse_ReportType_State.MsgBlockOnlyValue)
            {
                eReportSubType_State reportSubType;
                bool bRetVal = GenParse_ReportType_State.ParseByte(reportTypeByteValue, out reportSubType);
                if (bRetVal)
                {
                    reportType = new ReportType_State(onOffFlagValue, reportSubType);
                    return true;
                }

                // TODO handle error (parsing has failed)
                return false;
            }

            if (bits654 == GenParse_ReportType_Technical.MsgBlockOnlyValue)
            {
                eReportSubType_Technical reportSubType;
                bool bRetVal = GenParse_ReportType_Technical.ParseByte(reportTypeByteValue, out reportSubType);
                if (bRetVal)
                {
                    reportType = new ReportType_Technical(onOffFlagValue, reportSubType);
                    return true;
                }

                // TODO handle error (parsing has failed)
                return false;
            }

			// TODO handle error - unknown ReportType sub type (i.e. unknown MsgBlock bits 654 value)
			return false;
        }

        #endregion internal methods
    }
}
